package com.myqf2.d10_dbutils_xml.dbutils.增删改查工具类_通过方法反射_mybase框架原理;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

//持久层的一个工具类
public class CURDutils {

    /**
     * 对增删改操作的封装
     * @param sql sql语句
     * @param object sql语句中？所代表数据，参数的传递需要严格按照？的顺序进行传递
     * @param con 链接 ==>事务 con.setAutoCommit();
     *
     * 为什么不用Object,改用可变参数
     * 我们需要通过可变参数的个数来得到sql语句中？的个数
     *   update user set username=?,password=?,address=?,phone=? where id=?
     *       张三，1234，北京，111111，1
     */
    public static void executeUpdate(String sql, Connection con,Object... object) throws SQLException {
        //得到Preparstatement
        PreparedStatement pre = con.prepareStatement(sql);
        //问题来了？如何知道有几个问好呢？
        //给问号赋值
        // void setObject(int parameterIndex, Object x)
        //parameterIndex：表示第几个问号
        //x：该问号所对应的值
        for(int i=0;i<object.length;i++){
            pre.setObject(i+1,object[i]);
        }
        pre.executeUpdate();
    }


    /**
     *
     * @param bean 是用户需要和ResultSet映射的结果集
     * @param sql
     * @param con
     * @param obj
     * @return
     * @throws SQLException
     *
     *
     */
    public static List executeQuery(Object bean, String sql, Connection con, Object...obj) throws SQLException, InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException {
        PreparedStatement pre = con.prepareStatement(sql);
        List list=new ArrayList();
        for(int i=0;i<obj.length;i++){
            pre.setObject(i+1,obj[i]);
        }
        ResultSet rs=pre.executeQuery();
        //如何解决不同对象的属性不一致问题
        //如何将ResuleSet中的结果集封装成对象？
        //1.通过用户传进来的javaBean得到Class类型的对象
        //              技术迭代
        //抛出一个问题：如何给属性赋值？u.name="张三"==>u.setName("张三")==>Method.invoke()
        //向下转型==》代码可复用性不高，失去我们封装的初衷了
        //2.在Class对象中获取所有的方法===》能不能筛选出set方法？
        //3.找出所有的set方法对象之后，执行invoke方法
        Class beanClass = bean.getClass();
        Method[] methods = beanClass.getMethods();
        while(rs.next()){
                //及时的修改bean
            //每一次rs.next都是获取新的一行数据，需要用新的对象去接受
            Constructor constructor = beanClass.getConstructor();
            Object o = constructor.newInstance();

            for(Method m:methods){//user类中的五个set方法
                    if(m.getName().startsWith("set")){
                        //Object invoke(Object obj, Object... args)
                        //4.args是不是从rs中获取的值
                        //rs.getObject();//形参可以是1，2，3，4.。也可以是字段名
                        //不能用1，2，3这样的顺序是因为无法确定methods方法的顺序
                        //遍历到此时m就是setUsername();的Method方法实例
                        //m.getName()===>setUsername
                        //subString截取set后面的，toLowerCase转换成小写
                        String columnName=m.getName().substring(3).toLowerCase();//username 获取表名
                        m.invoke(o,rs.getObject(columnName));
                    }
                }
            list.add(o);
        }
        return list;
    }
}
